package com.hup.vd.m3u8;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.time.Duration;

/**
 * @author hugan
 * @date 2025/10/4
 */
@Slf4j
public class FfmpegUtil {

    /**
     * 检查ffmpeg, 并创建 CommandLine
     *
     * @apiNote 要手工把 ffmpeg.exe 放到 "./libs"
     */
    public static CommandLine createCommandLine() throws FfmpegException {
        //不放到jar里面: jar和仓库体积
        File ffmpeg = new File("./libs", "ffmpeg.exe");
        if (!ffmpeg.exists()) {
            throw new FfmpegException("", "找不到ffmpeg文件:" + ffmpeg.getAbsolutePath());
        }
        return CommandLine.parse(ffmpeg.getAbsolutePath());
    }

    /**
     * @param cmdLine 使用 {@link #createCommandLine()} 创建 CommandLine
     * @param desc 错误消息的前缀
     * @apiNote 调用注意, cmd中要使用临时文件名, 执行完后再重命名成目标文件
     */
    public static void exec(CommandLine cmdLine, File workingDirectory, String desc) throws FfmpegException {
        /*
        commons.exec问题: [输出流,错误流等]线程都是直接new的, 且不能复用, 整套DefaultExecutor都不能复用;
         */
        DefaultExecutor executor = DefaultExecutor.builder()
                .setWorkingDirectory(workingDirectory)
                .get();
        ExecuteWatchdog watchdog = ExecuteWatchdog.builder()
                .setTimeout(Duration.ofMinutes(10))
                .get();
        executor.setWatchdog(watchdog);

        // 捕获命令输出
        StringBuilder errorText = new StringBuilder();
        Exception err = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
            executor.setStreamHandler(streamHandler);
            executor.setExitValues(new int[]{0});

            // 执行命令
            int exitValue = executor.execute(cmdLine);
            log.info("exitValue={}", exitValue);

            /*
            中断执行时,文件会不完整, 只有exitValue=0 才是正常的文件
             */
            if (exitValue == 0) {
                return;
            } else {
                // 一般是中途错误
                errorText.append(outputStream.toString("GBK"));
            }
        } catch (Exception e) {
            try {
                //此处 解决不了ffmpeg的中文乱码,其他命令就没有乱码...
                errorText.append(outputStream.toString("GBK"));
                err = e;
            } catch (UnsupportedEncodingException ex) {
                log.error("编码异常?", ex);
            }
        } finally {
            IOUtils.closeQuietly(outputStream);
        }
        if (watchdog.killedProcess()) {
            errorText.insert(0, "执行超时, ");
        }
        //exitValue不为0,或有异常
        if (err == null) {
            throw new FfmpegException(desc, errorText.toString());
        } else {
            throw new FfmpegException(desc, errorText.toString(), err);
        }
    }

    public static class FfmpegException extends Exception {
        public FfmpegException(String desc, String message) {
            super(desc + "ffmpeg异常:\n" + message);
        }

        public FfmpegException(String desc, String message, Exception e) {
            super(desc + "ffmpeg异常:\n" + message, e);
        }
    }

}
